﻿#include"stdafx.h"
namespace LK
{
	//内存复制,pDestination指向目标内存，pSource指向源数据，sizeInBytes是按字节数表示的大小，源数据数和目标内存不能重叠
	void Memory::Copy(void* pDestination, const void* pSource, size_t SizeInBytes)
	{
#ifdef _VC
		memcpy_s(pDestination, SizeInBytes, pSource, SizeInBytes);
#else
		memcpy(pDestination, pSource, SizeInBytes);
#endif
	}
	//内存移动（内存复制的可能有重叠版本）
	void Memory::Move(void* pDestination, const void* pSource, size_t sizeInBytes)
	{
		if (!sizeInBytes)return;
#ifdef _VC
		memmove_s(pDestination, sizeInBytes, pSource, sizeInBytes);
#else
		memmove(pDestination, pSource, sizeInBytes);
#endif
	}
	void* Memory::Realloc(void* p, size_t size, size_t Length)
	{
#ifdef LJ_MEMORY_TEST
		u8* pu;
		p = LJ_MEMORY_TEST_CHECK(p);
#endif
		size_t len = size* Length;
#ifdef LJ_MEMORY_TEST
		len += LJ_MEMORY_TEST_BEFORE + LJ_MEMORY_TEST_AFTER + sizeof(size_t);
#endif
#ifdef MALLOC_280_H
		void*pp = ::dlrealloc((void*)p, len);
#else
		void*pp = ::realloc((void*)p, len);
#endif
		if (pp == NULL)
		{
			//再次尝试
			Sleep(100);
#ifdef MALLOC_280_H
			pp = ::dlrealloc((void*)p, len);
#else
			pp = ::realloc((void*)p, len);
#endif
			if (pp == NULL)throw POutOfMemoryException();
		}
#ifdef LJ_MEMORY_TEST
		*(size_t*)pp = len - LJ_MEMORY_TEST_AFTER;
		pp = (size_t*)pp + 1;
		for (size_t i = 0; i < LJ_MEMORY_TEST_BEFORE; ++i)
			((u8*)pp)[i] = LJ_MEMORY_TEST_MASK;
		pu = (u8*)pp + len - LJ_MEMORY_TEST_AFTER - sizeof(size_t);
		for (size_t i = 0; i < LJ_MEMORY_TEST_AFTER; ++i)
			pu[i] = LJ_MEMORY_TEST_MASK;
		pp = (u8*)pp + LJ_MEMORY_TEST_BEFORE;
#endif
		return pp;
	}
	void* Memory::Malloc(size_t size, size_t Length, size_t*ps)
	{
		if (Length == 0)return NULL;
		size_t len = Memory::GetResize(Length*size);
#ifdef LJ_MEMORY_TEST
		len += LJ_MEMORY_TEST_BEFORE + LJ_MEMORY_TEST_AFTER + sizeof(size_t);
#endif
#ifdef MALLOC_280_H
		void* p = ::dlmalloc(len);
#else
		void* p = ::malloc(len);
#endif
		if (p == NULL)
		{
			//再次尝试
			Sleep(100);
#ifdef MALLOC_280_H
			p = ::dlmalloc(len);
#else
			p = ::malloc(len);
#endif
			if (p == NULL)throw POutOfMemoryException();
		}
#ifdef LJ_MEMORY_TEST
		*(size_t*)p = len - LJ_MEMORY_TEST_AFTER;
		p = (size_t*)p + 1;
		for (size_t i = 0; i < LJ_MEMORY_TEST_BEFORE; ++i)
			((u8*)p)[i] = LJ_MEMORY_TEST_MASK;
		u8* pu = (u8*)p + len - LJ_MEMORY_TEST_AFTER - sizeof(size_t);
		for (size_t i = 0; i < LJ_MEMORY_TEST_AFTER; ++i)
			pu[i] = LJ_MEMORY_TEST_MASK;
		p = (u8*)p + LJ_MEMORY_TEST_BEFORE;
		if (ps)*ps = (len - LJ_MEMORY_TEST_BEFORE - LJ_MEMORY_TEST_AFTER - sizeof(size_t)) / size;
#else
		if (ps)*ps = len / size;
#endif
		return p;
	}
	void* Memory::Malloc(size_t size, size_t Length)
	{
		if (Length == 0)return NULL;
		size_t len = Length*size;
#ifdef LJ_MEMORY_TEST
		len += LJ_MEMORY_TEST_BEFORE + LJ_MEMORY_TEST_AFTER + sizeof(size_t);
#endif
#ifdef MALLOC_280_H
		void* p = ::dlmalloc(len);
#else
		void* p = ::malloc(len);
#endif
		if (p == NULL)
		{
			//再次尝试
			Sleep(100);
#ifdef MALLOC_280_H
			p = ::dlmalloc(len);
#else
			p = ::malloc(len);
#endif
			if (p == NULL)throw POutOfMemoryException();
		}
#ifdef LJ_MEMORY_TEST
		*(size_t*)p = len - LJ_MEMORY_TEST_AFTER;
		p = (size_t*)p + 1;
		for (size_t i = 0; i < LJ_MEMORY_TEST_BEFORE; ++i)
			((u8*)p)[i] = LJ_MEMORY_TEST_MASK;
		u8* pu = (u8*)p + len - LJ_MEMORY_TEST_AFTER - sizeof(size_t);
		for (size_t i = 0; i < LJ_MEMORY_TEST_AFTER; ++i)
			pu[i] = LJ_MEMORY_TEST_MASK;
		p = (u8*)p + LJ_MEMORY_TEST_BEFORE;
#endif
		return p;
	}
#ifdef LJ_MEMORY_TEST
	void* LJ_MEMORY_TEST_CHECK(void*p) {
		if (!p)return p;
		p = (u8*)p - LJ_MEMORY_TEST_BEFORE;
		for (size_t i = 0; i < LJ_MEMORY_TEST_BEFORE; ++i)
			if (((u8*)p)[i] != LJ_MEMORY_TEST_MASK)
			{
				std::cout << "释放内存时检测到写入越界：" << int(i - LJ_MEMORY_TEST_BEFORE) << "字节内容不符" << std::endl;
				break;
			}
		p = (u8*)p - sizeof(size_t);
		u8* pu = (u8*)p + *(size_t*)p;
		for (size_t i = LJ_MEMORY_TEST_AFTER - 1; i != 0;)
			if (pu[--i] != LJ_MEMORY_TEST_MASK) {
				std::cout << "释放内存时检测到写入越界：" << i + 1 << "字节内容不符" << std::endl;
				break;
			}
		return p;
	}
#endif
	void Memory::vFree(void*p)
	{
#ifdef LJ_MEMORY_TEST
		if (p == NULL)return;
		p = LJ_MEMORY_TEST_CHECK(p);
#endif
#ifdef MALLOC_280_H
		dlfree(p);
		static long long allsize;
		allsize += dlmalloc_footprint();
		if (allsize > MaxValues::UInt32) { allsize = 0; dlmalloc_trim(0); }
#else
		::free(p);
#endif
	}
}